using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data.SQLite;
using System.IO;
using System.Windows.Threading;
using Lime49.UI;
using Microsoft.Win32;
using Lime49;
using LockCrypt.Properties;
using LockCrypt.DAL;
using System.ComponentModel;
using LockCrypt.Core;

namespace LockCrypt {
    /// <summary>
    /// The first time setup wizard which allows a user to set up a database
    /// </summary>
    public partial class WinInstaller : Window {
        /// <summary>
        /// Initializes a new <see cref="WinInstaller"/>.
        /// </summary>
        public WinInstaller() {
            InitializeComponent();
            lstLanguages.ItemsSource = Constants.Languages.OrderBy(l=>l.Value.EnglishName);
            lstLanguages.SelectedValue = Settings.Default.Language;
            dbSelector.DatabasePath = System.IO.Path.Combine(System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "LockCrypt"), "LockCrypt.lce");
        }
        
        /// <summary>
        /// Moves to the previous page.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        protected void btnPrevious_Click(object sender, RoutedEventArgs e) {
            switch((tabWizard.SelectedItem as TabItem).Name.ToLower()) {
                case "tbpassword":
                    tbStart.IsSelected = true;
                    btnPrevious.Visibility = Visibility.Hidden;
                    break;
                case "tbdatabase":
                    tbStart.IsSelected = true;
                    btnPrevious.Visibility = Visibility.Hidden;
                    break;
                /*case "tbdatabase":
                    tbPassword.IsSelected = true;
                    btnPrevious.Visibility = Visibility.Visible;
                    break;*/
                case "tbfinish":
                    tbDatabase.IsSelected = true;
                    btnPrevious.Visibility = Visibility.Visible;
                    break;
            }
            btnNext.Content = I18nUtils.GetString("Strings", "Next");
        }

        /// <summary>
        /// Moves to the next page or finishes the wizard if the last page is active.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        protected void btnNext_Click(object sender, RoutedEventArgs e) {
            switch((tabWizard.SelectedItem as TabItem).Name.ToLower()) {
                case "tbstart":
                    Settings.Default.Language = lstLanguages.SelectedValue.ToString();
                    Settings.Default.Save();
                    WPFConfigurationManager.Configure();
                    //tbPassword.IsSelected = true;
                    tbDatabase.IsSelected = true;
                    // language
                    break;
                case "tbdatabase":
                    try {
                        Settings.Default.FirstRun = false;
                        WPFConfigurationManager.Configure(true);
                        if(Settings.Default.AutoOpenOnStartup && dbSelector.ValidateSettings()) {
                            Settings.Default.DatabaseConnectionString = dbSelector.Provider.ConnectionString;
                            DalConfigurationManager.Provider = dbSelector.Provider;
                            DalConfigurationManager.Provider.Encryption.EncryptionKey = dbSelector.EncryptionPassword;
                            bool createDb = false;
                            string databasePath = dbSelector.DatabasePath;// txtDBPath.Text;
                            if(DalConfigurationManager.IsProviderFileBased(dbSelector.DatabaseMode) && File.Exists(databasePath)) {
                                if(DialogBox.Show(this, I18nUtils.GetString("Strings", "FileExistsOverWriteFmt", databasePath), I18nUtils.GetString("Strings", "FileExists"), DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Question, DialogBoxButton.Yes) == DialogBoxButton.Yes) {
                                    File.Delete(databasePath);
                                    createDb = true;
                                }
                            } else {
                                createDb = true;
                            }
                            if(createDb) {
                                bool restartWorker = false;
                                BackgroundWorker worker = new BackgroundWorker();
                                worker.DoWork += (s, dwe) => {
                                    DalConfigurationManager.Provider.CreateDatabase();
                                    DataCreator.AddTemplates();
                                };
                                //todo: refactor this
                                Exception rweEx = null; // can't return from inside the delegate in runworker completed
                                worker.RunWorkerCompleted += (s, rwe) => {
                                    SetStatus(null);
                                    btnNext.IsEnabled = true;
                                    if(rwe.Error != null) {
                                        rweEx = rwe.Error;
                                    }
                                };
                                SetStatus(I18nUtils.GetString("Strings", "Working"));
                                btnNext.IsEnabled = false;
                                worker.RunWorkerAsync();
                                while(worker.IsBusy) {
                                    Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                                }
                                if(rweEx != null) {
                                    if(rweEx is LockCryptException && ((LockCryptException) rweEx).ErrorCode == 235) {
                                        switch (DialogBox.Show(this, I18nUtils.GetString("Strings", "TablesExistOverWritePrompt", databasePath), I18nUtils.GetString("Strings", "DatabaseExists"), DialogBox.DialogBoxType.YesNoCancel, DialogBox.DialogBoxIcon.Question, DialogBoxButton.Yes)) {
                                            case DialogBoxButton.Yes:
                                                restartWorker = true;
                                                break;
                                            case DialogBoxButton.Cancel:
                                                return;
                                        }
                                    } else {
                                        throw rweEx;
                                    }
                                }
                                if(restartWorker) {
                                    // this isn't the nicest part of this method...
                                    worker = new BackgroundWorker();
                                    worker.DoWork += (s, dwe) => {
                                        if(DalConfigurationManager.Provider is NetworkDatabase) {
                                            ((NetworkDatabase) DalConfigurationManager.Provider).RemoveDatabase();
                                        }
                                        DalConfigurationManager.Provider.CreateDatabase();
                                        DataCreator.AddTemplates();
                                    };
                                    worker.RunWorkerCompleted += (s, rwe) => {
                                        SetStatus(null);
                                        btnNext.IsEnabled = true;
                                        if(rwe.Error != null) {
                                            throw rwe.Error;
                                        }
                                    };
                                    SetStatus(I18nUtils.GetString("Strings", "Working"));
                                    btnNext.IsEnabled = false;
                                    worker.RunWorkerAsync();
                                    while(worker.IsBusy) {
                                        Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                                    }
                                }
                            }
                            tbFinish.IsSelected = true;
                            btnNext.Content = I18nUtils.GetString("Strings", "Finish");
                        }
                        Settings.Default.Save();
                    } catch(Exception ex) {
                        DialogBox.ShowAlert(this, I18nUtils.GetString("Errors", "ErrorCreatingDBFmt", ex.Message), I18nUtils.GetString("Errors", "Error"));
                    }
                    break;
                case "tbfinish":
                    if(Settings.Default.AutoOpenOnStartup && chkExampleData.IsChecked == true) {
                        IDbProvider provider = dbSelector.Provider;
                        Settings.Default.DatabaseConnectionString = provider.ConnectionString;
                        /*if(DalConfigurationManager.IsProviderFileBased(provider.DatabaseType)) {
                            Settings.Default.DatabasePath = ((FileBasedDatabase)provider).FileName;
                        }*/
                        Settings.Default.Save();
                        BackgroundWorker worker = new BackgroundWorker();
                        worker.DoWork += (s, dwe) => DataCreator.AddDummyData(false);
                        worker.RunWorkerCompleted += (s, rwe) => {
                            SetStatus(null);
                            btnNext.IsEnabled = true;
                            if(rwe.Error != null) {
                                DialogBox.ShowAlert(this, rwe.Error, I18nUtils.GetString("Errors", "Error"));
                                return;
                            }
                        };
                        SetStatus(I18nUtils.GetString("Strings", "Working"));
                        btnNext.IsEnabled = false;
                        worker.RunWorkerAsync();
                        while(worker.IsBusy) {
                            Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                        }
                    }
                    this.DialogResult = true;
                    break;
            }
            btnPrevious.Visibility = Visibility.Visible;
            // works - taken from elsewhere
            /*tabWizard.SelectedIndex = tabWizard.SelectedIndex + 1;
            btnPrevious.Visibility = Visibility.Visible;
            if(tabWizard.SelectedIndex == tabWizard.Items.Count - 1) {
                btnNext.Content = I18nUtils.GetString("Strings", "NextMnemonic");
                btnNext.IsEnabled = false;
            }*/
        }
        
        /// <summary>
        /// Opens a URL
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Navigation.RequestNavigateEventArgs"/> instance containing the event data.</param>
        private void btnClick(object sender, RoutedEventArgs e) {
            if(sender == btnHelpFile) {
                ApplicationCommands.Help.Execute(null, this);
            }
        }

        /// <summary>
        /// Opens the help file.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowHelp(object sender, ExecutedRoutedEventArgs e) {
            WPFUtils.OpenHelp(null);
        }

        /// <summary>
        /// Sets the text on the status message (null hides the statusbar and label).
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetStatus(string message) {
            if(message == null) {
                prgStatus.Visibility = Visibility.Collapsed;
                lblStatus.Visibility = Visibility.Collapsed;
            } else {
                prgStatus.Visibility = Visibility.Visible;
                lblStatus.Visibility = Visibility.Visible;
                lblStatus.Text = message;
            }
        }
    }
}
